package com.xj.core.orm.hibernate;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.transform.ResultTransformer;
import org.springframework.util.Assert;

import com.xj.util.Page;
import com.xj.util.ReflectionUtils;


/**
 * 封装hibernate的分页查询
 * @author caifei
 *
 * @param <T>
 * @param <PK>
 */
public class HibernateDao<T, PK extends Serializable> extends AbstractHibernateDao<T, PK> {

    public HibernateDao() {
        super();
    }
    
    public HibernateDao(final SessionFactory sessionFactory, final Class<T> entityClass) {
        super(sessionFactory, entityClass);
    }
    
    /**
     * 按map匹配分页查找
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public Page<T> findPage(final Page<T> page, final Map<String, Object> map) {
        Assert.notNull(page, "page不能为空");
        
        Criteria c = createCriteria(map);
        
        if (page.isAutoCount()) {
            long totalCount = countCriteriaResult(c);
            page.setTotalCount(totalCount);
        }
        
        setPageParameterToCriteria(c, page);

        List result = c.list();
        page.setResult(result);
        return page;
    }
    
    /**
     * 执行count查询获得本次Criteria查询所能获得的对象总数.
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected long countCriteriaResult(final Criteria c) {
        CriteriaImpl impl = (CriteriaImpl) c;

        // 先把Projection、ResultTransformer、OrderBy取出来,清空三者后再执行Count操作
        Projection projection = impl.getProjection();
        ResultTransformer transformer = impl.getResultTransformer();

        List<CriteriaImpl.OrderEntry> orderEntries = null;
        try {
            orderEntries = (List) ReflectionUtils.getFieldValue(impl, "orderEntries");
            ReflectionUtils.setFieldValue(impl, "orderEntries", new ArrayList());
        } catch (Exception e) {
            logger.error("不可能抛出的异常:{}", e.getMessage());
        }

        // 执行Count查询
        Long totalCountObject = (Long) c.setProjection(Projections.rowCount()).uniqueResult();
        long totalCount = (totalCountObject != null) ? totalCountObject : 0;

        // 将之前的Projection,ResultTransformer和OrderBy条件重新设回去
        c.setProjection(projection);

        if (projection == null) {
            c.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
        }
        if (transformer != null) {
            c.setResultTransformer(transformer);
        }
        try {
            ReflectionUtils.setFieldValue(impl, "orderEntries", orderEntries);
        } catch (Exception e) {
            logger.error("不可能抛出的异常:{}", e.getMessage());
        }

        return totalCount;
    }
    
    /**
     * 设置分页参数到Criteria对象,辅助函数.
     */
    protected Criteria setPageParameterToCriteria(final Criteria c, final Page<T> page) {
        //Assert.isTrue(page.getPageSize() > 0, "Page Size must larger than zero");
		if(page.getPageSize()>0){
			//hibernate的firstResult的序号从0开始
	        c.setFirstResult(page.getFirst() - 1);
	        c.setMaxResults(page.getPageSize());
		}
		if (page.isOrderBySetted()) {
            String[] orderByArray = StringUtils.split(page.getOrderBy(), ',');
            String[] orderArray = StringUtils.split(page.getOrder(), ',');

            Assert.isTrue(orderByArray.length == orderArray.length, "分页多重排序参数中,排序字段与排序方向的个数不相等");

            for (int i = 0; i < orderByArray.length; i++) {
                if (Page.ASC.equals(orderArray[i])) {
                    c.addOrder(Order.asc(orderByArray[i]));
                } else {
                    c.addOrder(Order.desc(orderByArray[i]));
                }
            }
        }
        return c;
    }
    
	/**
 	 * 通用查询分页的方法
 	 * @param hqls  查询的sql
 	 * @param pageNum  页数
 	 * @param pageSize 页面大小
 	 * @return 查询的数据集合
 	 */
 	public List<Object[]> findPageDataObject(Map<String, Object> map,String hqls, int pageNum, int pageSize) {
 		//StringBuilder hql = new StringBuilder(hqls);
 		// 将值设置进Query中
 		Query query = this.getSession().createSQLQuery(hqls);
 		query = whereSQL(map,query);
 		// 当pageNum和pageSize同时为-1时，查询所有
 		if (-1 == pageNum && -1 == pageSize) {
 			return query.list();
 		} else if (pageSize > 0) {
 			// 当pageSize大于0时
 			int start = 0;
 			if (pageNum > 1) {
 				// pageNum大于1
 				start = (pageNum - 1) * pageSize;
 			}
 			query.setFirstResult(start);
 			query.setMaxResults(pageSize);
 			return query.list();
 		} else {
 			// pageSize小于或等于0时
 			return null;
 		}
 	 }
 	
 	private Query whereSQL(Map<String, Object> map,Query query){
 		Set<Entry<String, Object>> set = map.entrySet();
 		int i=0;
		for (Entry<String, Object> entry : set) {
			Object obj = entry.getValue();
			if (obj != null && StringUtils.isNotEmpty(obj.toString())) {
				String[] key=entry.getKey().split("_");
				if (key.length == 2) {
					if (StringUtils.equals("li", key[1])) {
						String li="%" + entry.getValue() + "%";
						query.setString(i, li);
					}else if(StringUtils.equals("lis", key[1])) {
						String li=entry.getValue() + "%";
						query.setString(i, li);
					}
					else{
						if (StringUtils.equalsIgnoreCase(obj.toString(),"String")) {
							query.setString(i,obj.toString());
						}
						else if (StringUtils.equalsIgnoreCase(obj.toString(),"Integer")) {
							query.setInteger(i,(Integer) obj);
						}
						else if (StringUtils.equalsIgnoreCase(obj.toString(),"Long")) {
							query.setLong(i,(Long) obj);
						}
						else if (StringUtils.equalsIgnoreCase(obj.toString(),"Float")) {
							query.setFloat(i,(Float) obj);
						}
						else if (StringUtils.equalsIgnoreCase(obj.toString(),"Double")) {
							query.setDouble(i,(Double) obj);
						}
						else if (StringUtils.equalsIgnoreCase(obj.toString(),"Boolean")) {
							query.setBoolean(i,(Boolean) obj);
						}
						else{
							query.setString(i,obj.toString());
						}
					}
				}
				else{
					if (StringUtils.equalsIgnoreCase(obj.toString(),"String")) {
						query.setString(i,obj.toString());
					}
					else if (StringUtils.equalsIgnoreCase(obj.toString(),"Integer")) {
						query.setInteger(i,(Integer) obj);
					}
					else if (StringUtils.equalsIgnoreCase(obj.toString(),"Long")) {
						query.setLong(i,(Long) obj);
					}
					else if (StringUtils.equalsIgnoreCase(obj.toString(),"Float")) {
						query.setFloat(i,(Float) obj);
					}
					else if (StringUtils.equalsIgnoreCase(obj.toString(),"Double")) {
						query.setDouble(i,(Double) obj);
					}
					else if (StringUtils.equalsIgnoreCase(obj.toString(),"Boolean")) {
						query.setBoolean(i,(Boolean) obj);
					}
					else{
						query.setString(i,obj.toString());
					}
				}
				i++;
			}
		}	
		return query;
	}
    
}
